package com.learn.springbootcache.service;

import com.learn.springbootcache.bean.Employee;
import com.learn.springbootcache.mapper.EmployeeMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author Jmy
 */
@CacheConfig(cacheNames = {"emp"})
@Service
public class EmployeeService {

    private static final Logger logger = LoggerFactory.getLogger(EmployeeService.class);

    @Autowired
    EmployeeMapper employeeMapper;

    /**
     *      @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据，默认按照参数的值作为key去查询缓存，
     *      如果没有就运行方法并将结果放入缓存；以后再来调用就可以直接使用缓存中的数据；
     *
     *      几个属性：
     *    cacheNames/value：指定缓存组件的名字;将方法的返回结果放在哪个缓存中，是数组的方式，可以指定多个缓存；
     *
     *    key：缓存数据使用的key；可以用它来指定。默认是使用方法参数的值  1-方法的返回值
     *            编写SpEL； #i d;参数id的值   #a0  #p0  #root.args[0]
     *            getEmp[2]
     *
     *    keyGenerator：key的生成器；可以自己指定key的生成器的组件id
     *            key/keyGenerator：二选一使用;
     *
     *
     *    cacheManager：指定缓存管理器；或者cacheResolver指定获取解析器
     *
     *    condition：指定符合条件的情况下才缓存；
     *            ,condition = "#id>0"
     *        condition = "#a0>1"：第一个参数的值》1的时候才进行缓存
     *
     *    unless:否定缓存；当unless指定的条件为true，方法的返回值就不会被缓存；可以获取到结果进行判断
     *            unless = "#result == null"
     *            unless = "#a0==2":如果第一个参数的值是2，结果不缓存；
     */
    @Cacheable(key = "#p0",unless = "#result == null")
    public Employee getEmpById(Integer id){
        Employee emp = employeeMapper.getEmployeeById(id);
        return emp;
    }

    /**
     * @CachePut：既调用方法，又更新缓存数据；同步更新缓存
     * 修改了数据库的某个数据，同时更新缓存；
     * 运行时机：
     *  1、先调用目标方法
     *  2、将目标方法的结果缓存起来
     */
    @CachePut(key = "#result.id")
    public Employee updateEmp(Employee employee){
        int count = employeeMapper.updateEmployee(employee);
        logger.info("更新数据:" + count);
        return employee;
    }

    /**
     * @CacheEvict：缓存清除
     *  key：指定要清除的数据
     *  allEntries = true：指定清除这个缓存中所有的数据
     *  beforeInvocation = false：缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true：
     *      代表清除缓存操作是在方法运行之前执行，无论方法是否出现异常，缓存都清除
     *
     *
     */
    @CacheEvict(key = "#root.args[0]")
    public void delEmployee(Integer id){
        employeeMapper.delEmployee(id);
    }

    /**
     *  @Caching 定义复杂的缓存规则
      */
    @Caching(
            cacheable = {
                    @Cacheable(key = "#name")
            }
    )
    public List<Employee> getEmpByName(String name){
        return employeeMapper.empList(name);
    }

    @RabbitListener(queues = "use.news")
    public void receive(Employee emp){
        logger.info("接受mq消息：{}", emp);
    }

    @RabbitListener(queues = "use")
    public void receive02(Message message){
        logger.info("接受MQ消息body:{}", message.getBody());
        logger.info("接受MQ消息getMessageProperties:{}", message.getMessageProperties());
    }

    @RabbitListener(queues = "europe.news")
    public void news(Message message){
        logger.info("接受MQ消息body:{}", message.getBody());
        logger.info("接受MQ消息getMessageProperties:{}", message.getMessageProperties());
    }

}
